package scenebuilders;
import javax.media.j3d.Geometry;
import javax.media.j3d.IndexedGeometryArray;
import javax.media.j3d.IndexedQuadArray;
import javax.media.j3d.Shape3D;
import javax.vecmath.Point3f;
import javax.vecmath.TexCoord2f;
import javax.vecmath.Vector3f;

public class ShapeBuilder {
	IndexedGeometryArray plane = null;
	double dx = 0.1d; 
	double dy = 0.1d;
	int tCellsCountX = 1;
	int tCellsCountY = 1;


	void SetMyDxDy(float dx, float dy) {
		this.dx = dx;
		this.dy = dy;
	}
	
	public void SetMyTextureCellsCount(int tCellsCountX, int tCellsCountY) {
		this.tCellsCountX = tCellsCountX;
		this.tCellsCountY = tCellsCountY;
	}	

	public Shape3D CreateRectPlane(float sirka, float vyska) {
		Point3f TL = new Point3f(-sirka / 2, +vyska / 2, 0);
		Point3f BR = new Point3f(+sirka / 2, -vyska / 2, 0);
		Point3f BL = new Point3f(-sirka / 2, -vyska / 2, 0);
		Point3f TR = new Point3f(+sirka / 2, +vyska / 2, 0);

		Vector3f n = GetNorm(TL, BL, BR, TR);
		Shape3D shape = new Shape3D();
		shape.setGeometry(createGeometry(TL, BR, n));
		return shape;
	}

	Geometry createGeometry(Point3f TL, Point3f BR, Vector3f n) {
		final float top = TL.y, left = TL.x;
		final float bottom = BR.y, right = BR.x;
		final int X = (int) Math.round(((right - left) / dx)) + 1;
		final int Y = (int) Math.round(((top - bottom) / dy)) + 1;
		int format = IndexedQuadArray.COORDINATES | IndexedQuadArray.NORMALS | IndexedQuadArray.TEXTURE_COORDINATE_2;
		plane = new IndexedQuadArray(X * Y, format, (X - 1) * (Y - 1) * 4);

		// Definuje vsetky vrcholy plochy - ich suradnice a normaly
		int i = 0;
		double x = left, y = top;
		for (int row = 0; row < Y; row++, y -= dy, x = left) {
			for (int col = 0; col < X; col++, x += dx) {
				plane.setCoordinate(i, new Point3f((float)x, (float)y, 0.0f));
				plane.setNormal(i, n);	i++;
			}			
		}
		
		// Pre kazdy vrchol definuje texel textury, teda ktory bod textury sa mapuje
		// na dany vrchol. Bod textury sa definuje poomocou texCoord z intervalu <0,1>.
		i = 0;
		int tCellSizeX = X / tCellsCountX;
		int tCellSizeY = Y / tCellsCountY;
		for (int vRow = 0; vRow < Y; vRow++) {
			float texCoordY = 1 - ((float) (vRow % tCellSizeY)) / tCellSizeY;
			for (int vCol = 0; vCol < X; vCol++) {
				float texCoordX = ((float) (vCol % tCellSizeX)) / tCellSizeX;
				plane.setTextureCoordinate(0, i++, new TexCoord2f(texCoordX, texCoordY));
			}			
		}
		
		// Priraduje vrcholy jednotlivym ploskam. Plosku tvoria 4 vrholy.
		// Jeden vrchol mozno opakovane pouzit vo viacerych ploskach.
		i = 0;
		for (int row = 0; row < (Y - 1); row++) {
			for (int col = 0; col < (X - 1); col++) {
				SetIndex(i++, row * X + col);
				SetIndex(i++, (row + 1) * X + col);
				SetIndex(i++, (row + 1) * X + col + 1);
				SetIndex(i++, row * X + col + 1);
			}
		}
		return plane;
	}

	private void SetIndex(int index, int dataPtr) {
		plane.setCoordinateIndex(index, dataPtr);
		plane.setTextureCoordinateIndex(0, index, dataPtr);
	}

	private Vector3f GetNorm(Point3f A, Point3f B, Point3f C, Point3f D) {
		Vector3f a = new Vector3f(A.x - B.x, A.y - B.y, A.z - B.z);
		Vector3f b = new Vector3f(C.x - B.x, C.y - B.y, C.z - B.z);
		Vector3f n = new Vector3f();
		n.cross(b, a);
		n.normalize();
		n.scale(+1);
		return n;
	}
}
